/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package jturbofile.net;

import java.awt.TrayIcon.MessageType;
import java.io.File;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;
import jturbofile.Config;
import jturbofile.gui.LogPanel;
import jturbofile.gui.TrayGUI;

/**
 *
 * @author Rolf
 */
public class FileHandler implements Handler {

    private Map<String, OpenFile> openFiles;
    
    public FileHandler() {
        openFiles = new HashMap<String, OpenFile>();
    }
    
    public boolean handlePacket(Packet p, PeerThread pt) {
        switch(p.getType()) {
            
            case FILEBEGIN:
                fileBegin(p, pt);
                break;
            
            case FILEPART:
                filePart(p, pt);
                break;
                
            case FILEEND:
                fileEnd(p, pt);
                break;
                
            case FILECANCEL:
                fileCancel(p, pt);
                break;
                
            default:
                return false;
        }
        
        return true;
    }

    private void fileCancel(Packet p, PeerThread pt) {
        String id = p.getOptions().get(0)+"-"+pt.getHostAddress();
        LogPanel.singleton().logln("Filecancel ["+id+"]");
        
        if( !openFiles.containsKey(id) ) {
            LogPanel.singleton().logln("[End] There is no open file matching ["+id+"]");
        }
        else {
            OpenFile of = openFiles.remove(id);
            
            File f = new File(of.getPath());
            boolean ok = f.delete();
            
            pt.getConnectedUserUI().getIncommingLabel().setText("");
            pt.getConnectedUserUI().getIncommingProgress().setValue(0);
            pt.getConnectedUserUI().getIncommingProgress().setString("0%");
            
            if( ok ) {
                LogPanel.singleton().logln("Succesfully cancelled send, and deleted file.");
            }
            else {
                LogPanel.singleton().logln("Send was cancelled but file couldnt be deleted");
            }
        }
    }

    private String findNameFromPath(String path) {
        String fileName = path;
        
        fileName = fileName.replaceAll("\\\\", "/");
        
        if( fileName.lastIndexOf("/") != -1) {
            fileName = fileName.substring(fileName.lastIndexOf("/")+1);
        }
        
        return fileName;
    }
    
    private void fileBegin(Packet p, PeerThread pt) {
        String path = p.getOptions().get(0);
        String fileName = findNameFromPath(path);
        String id = p.getOptions().get(0)+"-"+pt.getHostAddress();
        long totalSize = Long.parseLong(p.getOptions().get(1));
        
        OpenFile of = new OpenFile("", fileName, totalSize, 0);
        
        LogPanel.singleton().logln("Filebegin ["+id+"]: "+fileName);
        
        if( openFiles.containsKey(id) ) {
            LogPanel.singleton().logln("Already have a file open matching ["+id+"]");
            Packet reject = new Packet(Packet.PacketType.FILEREJECT);
            reject.addOption(path);
            pt.sendPacket(reject);
        }
        else {
            //Create file to add data too
            Config conf = Config.singleton();
            
            try {
                File userDir = new File(conf.getValue("path") + "/" + pt.getHostAddress());

                if( !userDir.exists() ) {
                    userDir.mkdirs();
                }

                File newFile = new File(userDir.getAbsolutePath() + "/" + fileName);
                
                int i = 0;
                
                //Find a free filename to save to
                while(true) {
                    if( newFile.exists() ) {
                        newFile = new File(userDir.getAbsolutePath() + "/" + i + "-" + fileName );
                        i++;
                    }
                    else {
                        break;
                    }
                }
                
                newFile.createNewFile();
                
                of.setPath(newFile.getAbsolutePath());
                of.setId(id);
                of.setTimeStamp(0);
                
                openFiles.put(id, of);
                
                Packet accept = new Packet(Packet.PacketType.FILEACCEPT);
                accept.addOption(path);
                pt.sendPacket(accept);
                
                pt.getConnectedUserUI().getIncommingLabel().setText(of.getFileName());
                pt.getConnectedUserUI().getIncommingProgress().setString(of.getReceivedSize()+" / "+of.getTotalSize()+" - 0%");
            }
            catch(Exception e) {
                LogPanel.singleton().logln("Error creating file: "+e);
                Packet reject = new Packet(Packet.PacketType.FILEREJECT);
                reject.addOption(path);
                pt.sendPacket(reject);
            }
        }
    }

    private void filePart(Packet p, PeerThread pt) {
        String id = p.getOptions().get(0)+"-"+pt.getHostAddress();
        
        //LogPanel.singleton().logln("Filepart ["+id+"] ["+p.getData().length+"]");
        
        if( !openFiles.containsKey(id) ) {
            LogPanel.singleton().logln("[Part] There is no open file matching ["+id+"]");
        }
        else {
            //Add file data to file
            try {
                OpenFile of = openFiles.get(id);
                FileOutputStream out = new FileOutputStream( of.getPath(), true );
                
                byte[] data = p.getData();
                
                out.write(data);
                out.flush();
                out.close();
                
                of.setReceivedSize(of.getReceivedSize()+data.length);

                int percent = (int)(of.getReceivedSize() / (float) of.getTotalSize() * 100.0f);
                
                long now = System.currentTimeMillis();
                long timeStamp = of.getTimeStamp();

                float speed = (float)data.length / 1024.0f / (now - timeStamp) * 1000.0f;
                
                String speedStr = "kb";
                if( speed > 1024.0f ) {
                    speedStr = "mb";
                    speed /= 1024.0f;
                }
                if( speed > 1024.0f ) {
                    speedStr = "gb";
                    speed /= 1024.0f;
                }
                if( speed > 1024.0f ) {
                    speedStr = "tb";
                    speed /= 1024.0f;
                }
                    
                speed = ((long)(speed * 10)) / 10.0f;

                pt.getConnectedUserUI().getIncommingProgress().setValue(percent);
                pt.getConnectedUserUI().getIncommingProgress().setString(of.getReceivedSize()+" / "+of.getTotalSize()+" ["+speed+" "+speedStr+"/sec] - "+percent+"% Compression ["+p.getCompressionType()+"]");
                
                of.setTimeStamp(now);
                
            }
            catch(Exception e) {
                LogPanel.singleton().logln("Error opening file for appending ["+id+"]: "+e);
            }
        }
    }

    private void fileEnd(Packet p, PeerThread pt) {
        String id = p.getOptions().get(0)+"-"+pt.getHostAddress();
        LogPanel.singleton().logln("Fileend ["+id+"]");
        
        if( !openFiles.containsKey(id) ) {
            LogPanel.singleton().logln("[End] There is no open file matching ["+id+"]");
        }
        else {
            OpenFile of = openFiles.remove(id);
            
            LogPanel.singleton().logln("Succesfully received file: ["+of.getPath()+"]");
            
            pt.getConnectedUserUI().getIncommingLabel().setText("");
            pt.getConnectedUserUI().getIncommingProgress().setValue(0);
            pt.getConnectedUserUI().getIncommingProgress().setString("0%");
            
            TrayGUI.singleton().displayMessage("File received", "Succesfully received the file ["+of.getFileName()+"]", MessageType.INFO);
        }
    }

}
